{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Jaeger-query with trace DSL\n",
    "\n",
    "This notebook loads a trace from Jaeger query service via gRPC and runs analysis on it."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Install library to the local maven repository\n",
    "This step is only needed if trace DSL source code has been modified.\n",
    "Open terminal in Jupyter and run the following command:\n",
    "```\n",
    "cd work && ./mvnw clean install -DskipTests\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%loadFromPOM\n",
    "<dependency>\n",
    "  <groupId>com.google.protobuf</groupId>\n",
    "  <artifactId>protobuf-java</artifactId>\n",
    "  <version>3.11.4</version>\n",
    "</dependency>\n",
    "<dependency>\n",
    "  <groupId>com.google.protobuf</groupId>\n",
    "  <artifactId>protobuf-java-util</artifactId>\n",
    "  <version>3.11.4</version>\n",
    "</dependency>\n",
    "<dependency>\n",
    "  <groupId>io.grpc</groupId>\n",
    "  <artifactId>grpc-protobuf</artifactId>\n",
    "  <version>1.28.0</version>\n",
    "</dependency>\n",
    "<dependency>\n",
    "  <groupId>io.grpc</groupId>\n",
    "  <artifactId>grpc-netty</artifactId>\n",
    "  <version>1.28.0</version>\n",
    "</dependency>\n",
    "<dependency>\n",
    "  <groupId>io.grpc</groupId>\n",
    "  <artifactId>grpc-stub</artifactId>\n",
    "  <version>1.28.0</version>\n",
    "</dependency>\n",
    "\n",
    "<dependency>\n",
    "    <groupId>io.prometheus</groupId>\n",
    "    <artifactId>simpleclient_httpserver</artifactId>\n",
    "    <version>0.7.0</version>\n",
    "</dependency>\n",
    "<dependency>\n",
    "    <groupId>org.apache.tinkerpop</groupId>\n",
    "    <artifactId>tinkergraph-gremlin</artifactId>\n",
    "    <version>3.4.3</version>\n",
    "</dependency>\n",
    "<dependency>\n",
    "    <groupId>log4j</groupId>\n",
    "    <artifactId>log4j</artifactId>\n",
    "    <version>1.2.17</version>\n",
    "</dependency>\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "class io.jaegertracing.analytics.gremlin.Keys\n"
     ]
    }
   ],
   "source": [
    "%maven io.jaegertracing:jaeger-tracedsl:0.4.0\n",
    "%maven io.jaegertracing:jaeger-proto:0.4.0\n",
    "\n",
    "System.out.println(io.jaegertracing.analytics.gremlin.Keys.class);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Run analysis\n",
    "It calculates maximum trace height and network latencies. It connects to Jaeger query service via gRPC."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Error type, traceID and error count:\n",
      "error type: redis timeout\n",
      "\tTraceID: fc4df2212ebf40, count 3\n",
      "\tTraceID: 4e916ba6d8c18297, count 2\n",
      "\tTraceID: 72e82f15fdd252b1, count 2\n",
      "\tTraceID: 6b163ddc815f46, count 3\n",
      "\tTraceID: 2bc6bec49b121f07, count 3\n",
      "\tTraceID: c61ac8391634353, count 3\n",
      "\tTraceID: 4921177f60655be1, count 3\n",
      "\tTraceID: 1145bf4bdc8f9c21, count 2\n",
      "\tTraceID: 3bb5668d877b6346, count 2\n",
      "\tTraceID: 557044403cb65f4c, count 2\n",
      "\tTraceID: 3db57c32b396fa5, count 2\n",
      "\tTraceID: 39d5cdef7923c0e, count 3\n",
      "\tTraceID: 47baf4cd727ee0e4, count 2\n",
      "\tTraceID: 18c254d03210b078, count 2\n",
      "\tTraceID: 6836738e2b256fb0, count 2\n",
      "\tTraceID: 4c758ababa3f04c0, count 2\n",
      "\tTraceID: 3a20db525f6344db, count 3\n",
      "\tTraceID: 20402485446b76b3, count 2\n",
      "\tTraceID: 241bc51af4d7b288, count 2\n",
      "\tTraceID: 5c4c962b8064ac8f, count 2\n",
      "\tTraceID: 4a0c5a9b8a33727c, count 2\n",
      "\tTraceID: 472b4e7acd0a2a25, count 2\n",
      "\tTraceID: 64b286ddd2a6d5c5, count 3\n",
      "\tTraceID: 7773d4961586ba9b, count 3\n",
      "\tTraceID: 5b43f81de78c004d, count 2\n",
      "\tTraceID: 625e8ecf62bde6b0, count 2\n",
      "\tTraceID: b3d835de2ba19c4, count 2\n",
      "\tTraceID: 52f4268093b1c3c7, count 3\n",
      "\tTraceID: 26f4b2515b251a67, count 3\n",
      "\tTraceID: 7fbb7e36bcdd2fe, count 2\n",
      "\tTraceID: 1c41c6c8daf4b684, count 3\n",
      "\tTraceID: 67f8f85c3024d952, count 3\n",
      "\tTraceID: 2c1c646b236a5a81, count 3\n",
      "\tTraceID: d081c5667f34e7a, count 3\n",
      "\tTraceID: 36d717fd151065a6, count 2\n",
      "\tTraceID: 431651c4363a8042, count 3\n",
      "\tTraceID: 514eee98c64a877c, count 2\n",
      "\tTraceID: 7da57edb0b7c953, count 3\n",
      "\tTraceID: 29c083d54a331210, count 3\n",
      "\tTraceID: 496ce5c3aa685676, count 2\n",
      "\tTraceID: 3bcaa67d7a8c921b, count 3\n",
      "\tTraceID: 82366390f998667, count 3\n",
      "\tTraceID: 5da85ab7efa0ceaa, count 3\n",
      "\tTraceID: 4224c9f0081148e1, count 3\n",
      "Trace height = 4\n",
      "Network latencies = {Name{client='frontend', server='route'}=[3.04E-4, 3.4E-4, 1.23E-4, 4.94E-4, 4.83E-4, 3.94E-4, 4.55E-4, 3.62E-4, 1.42E-4, 3.9E-4, 4.4E-4, 4.01E-4, 1.17E-4, 4.03E-4, 3.97E-4, 1.73E-4, 3.93E-4, 1.21E-4, 1.4E-4, 0.00101, 8.9E-4, 0.001036, 1.88E-4, 3.3E-4, 9.09E-4, 5.87E-4, 3.13E-4, 3.5E-4, 3.85E-4, 2.02E-4, 3.25E-4, 3.89E-4, 3.92E-4, 4.53E-4, 2.12E-4, 0.001518, 8.54E-4, 4.06E-4, 3.55E-4, 4.33E-4, 1.07E-4, 0.00175, 2.9E-4, 2.21E-4, 3.57E-4, 3.29E-4, 3.67E-4, 0.001295, 1.16E-4, 4.6E-4, 3.66E-4, 9.01E-4, 4.07E-4, 1.91E-4, 3.43E-4, 1.32E-4, 4.45E-4, 4.24E-4, 3.79E-4, 3.22E-4, 5.36E-4, 9.06E-4, 3.08E-4, 3.65E-4, 4.71E-4, 1.65E-4, 2.56E-4, 4.43E-4, 3.53E-4, 2.0E-4, 3.21E-4, 1.41E-4, 3.23E-4, 3.2E-4, 1.95E-4, 4.18E-4, 2.41E-4, 4.34E-4, 2.92E-4, 2.65E-4, 3.73E-4, 1.31E-4, 4.49E-4, 2.5E-4, 3.12E-4, 3.82E-4, 2.77E-4, 1.37E-4, 3.69E-4, 9.7E-5, 3.07E-4, 3.84E-4, 1.33E-4, 4.32E-4, 1.69E-4, 4.05E-4, 3.0E-4, 1.25E-4, 2.88E-4, 9.42E-4, 5.31E-4, 0.001006, 2.63E-4, 3.49E-4, 0.001087, 3.7E-4, 8.67E-4, 1.26E-4, 4.2E-4, 9.48E-4, 1.67E-4, 6.52E-4, 0.001073, 1.77E-4, 0.001069, 8.86E-4, 3.8E-4, 3.83E-4, 1.43E-4, 4.51E-4, 9.62E-4, 2.53E-4, 3.03E-4, 3.05E-4, 3.76E-4, 2.95E-4, 3.87E-4, 4.13E-4, 3.64E-4, 4.12E-4, 2.13E-4, 3.81E-4, 2.42E-4, 3.52E-4, 3.45E-4, 4.09E-4, 2.68E-4, 4.17E-4, 3.32E-4, 1.27E-4, 4.29E-4, 4.36E-4, 1.34E-4, 3.99E-4, 6.57E-4, 3.44E-4, 3.18E-4, 8.93E-4, 5.89E-4, 3.98E-4, 5.17E-4, 3.58E-4, 3.01E-4, 2.85E-4, 0.001411, 6.6E-4, 4.0E-4, 0.00153, 4.79E-4, 2.38E-4, 2.81E-4, 0.003071, 5.16E-4, 0.001182, 2.82E-4, 6.03E-4, 1.78E-4, 0.001321, 9.78E-4, 0.001342, 2.54E-4, 0.002787, 1.94E-4, 4.64E-4, 3.71E-4, 2.32E-4, 0.001099, 1.58E-4, 5.18E-4, 4.37E-4, 2.27E-4, 4.59E-4, 3.95E-4, 2.15E-4, 9.39E-4, 6.27E-4, 2.45E-4, 4.85E-4, 3.91E-4, 3.47E-4, 1.75E-4, 2.43E-4, 5.65E-4, 3.78E-4, 3.59E-4, 1.57E-4, 2.22E-4, 4.02E-4, 4.84E-4, 2.16E-4, 1.79E-4, 2.3E-4, 1.29E-4, 3.51E-4, 3.41E-4, 7.15E-4, 4.73E-4, 1.45E-4, 2.84E-4, 8.99E-4, 2.89E-4, 2.39E-4, 1.36E-4, 5.52E-4, 5.78E-4, 6.95E-4, 2.19E-4, 1.08E-4, 9.93E-4, 2.93E-4, 3.96E-4, 1.9E-4, 3.27E-4, 3.39E-4, 3.74E-4, 8.17E-4, 0.001641, 0.001308, 8.74E-4, 2.18E-4, 3.63E-4, 4.67E-4, 2.8E-4, 5.4E-4, 3.37E-4, 3.1E-4, 3.6E-4, 1.24E-4, 3.24E-4, 1.72E-4, 4.38E-4, 3.33E-4, 8.1E-4, 5.33E-4, 6.53E-4, 4.65E-4, 0.00285, 0.002043, 1.13E-4, 0.00167, 0.001022, 2.98E-4, 5.73E-4, 0.002011, 8.75E-4, 1.35E-4, 5.81E-4, 6.47E-4, 1.68E-4, 4.7E-4, 4.77E-4, 2.31E-4, 0.001625, 4.08E-4, 2.75E-4, 1.14E-4, 7.52E-4, 3.72E-4, 2.06E-4, 1.63E-4, 1.84E-4, 3.54E-4, 2.25E-4, 1.7E-4, 2.66E-4, 3.77E-4, 1.82E-4, 1.62E-4, 3.11E-4, 1.66E-4, 9.52E-4, 4.92E-4, 3.68E-4, 6.91E-4, 6.11E-4, 0.001114, 3.35E-4, 6.04E-4, 8.68E-4, 5.42E-4, 0.001049, 8.36E-4, 7.66E-4, 4.3E-4, 1.87E-4, 4.93E-4, 5.35E-4, 8.41E-4, 4.88E-4, 4.61E-4, 2.05E-4, 2.36E-4, 9.38E-4, 0.001138, 4.23E-4, 1.18E-4, 1.8E-4, 3.28E-4, 2.08E-4, 4.66E-4, 1.92E-4, 5.22E-4], Name{client='frontend', server='customer'}=[8.25E-4, 0.001034, 3.99E-4, 4.49E-4, 5.27E-4, 3.46E-4, 3.93E-4, 0.001379, 6.19E-4, 1.15E-4, 8.6E-4, 3.69E-4, 3.47E-4, 9.97E-4, 3.36E-4, 3.51E-4, 3.38E-4, 4.69E-4, 2.81E-4, 3.27E-4, 3.71E-4, 7.99E-4, 3.23E-4, 3.33E-4, 4.21E-4, 4.11E-4, 3.55E-4, 2.99E-4, 3.94E-4, 1.94E-4, 1.99E-4, 5.71E-4, 4.45E-4, 2.43E-4, 8.88E-4, 4.94E-4, 4.09E-4, 8.81E-4, 3.57E-4, 4.92E-4, 1.31E-4, 4.98E-4], Name{client='frontend', server='driver'}=[4.28E-4, 0.001504, 4.5E-4, 4.21E-4, 4.74E-4, 3.17E-4, 0.005151, 4.12E-4, 9.67E-4, 7.28E-4, 3.83E-4, 5.31E-4, 4.73E-4, 4.67E-4, 3.08E-4, 1.66E-4, 5.65E-4, 4.78E-4, 4.03E-4, 6.04E-4, 4.31E-4, 5.04E-4, 8.23E-4, 4.27E-4, 4.15E-4, 7.64E-4, 4.44E-4, 1.25E-4, 1.75E-4, 3.82E-4, 2.02E-4, 3.24E-4, 1.95E-4, 5.76E-4, 0.001116, 3.38E-4, 3.58E-4, 4.84E-4, 2.5E-4, 3.73E-4, 7.31E-4, 5.66E-4]}\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "java.io.PrintStream@1fdec01f"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import com.google.protobuf.ByteString;\n",
    "import io.grpc.ManagedChannel;\n",
    "import io.grpc.ManagedChannelBuilder;\n",
    "import io.jaegertracing.analytics.*;\n",
    "import io.jaegertracing.analytics.NetworkLatency.Name;\n",
    "import io.jaegertracing.analytics.gremlin.GraphCreator;\n",
    "import io.jaegertracing.analytics.model.Converter;\n",
    "import io.jaegertracing.analytics.model.Trace;\n",
    "import io.jaegertracing.api_v2.Model.Span;\n",
    "import io.jaegertracing.api_v2.Query.GetTraceRequest;\n",
    "import io.jaegertracing.api_v2.Query.SpansResponseChunk;\n",
    "import io.jaegertracing.api_v2.QueryServiceGrpc;\n",
    "import io.jaegertracing.api_v2.Query.FindTracesRequest;\n",
    "import io.jaegertracing.api_v2.QueryServiceGrpc.QueryServiceBlockingStub;\n",
    "import io.jaegertracing.api_v2.Query.TraceQueryParameters;\n",
    "import io.opentracing.tag.Tags;\n",
    "import java.util.ArrayList;\n",
    "import java.util.Iterator;\n",
    "import java.util.List;\n",
    "import java.util.Map;\n",
    "import java.util.Set;\n",
    "import org.apache.tinkerpop.gremlin.structure.Graph;\n",
    "\n",
    "String queryHostPort = \"172.17.0.1:16686\";\n",
    "\n",
    "ManagedChannel channel;\n",
    "channel = ManagedChannelBuilder.forTarget(queryHostPort).usePlaintext().build();\n",
    "QueryServiceBlockingStub queryService = QueryServiceGrpc.newBlockingStub(channel);\n",
    "\n",
    "TraceQueryParameters query = TraceQueryParameters.newBuilder().setServiceName(\"frontend\")\n",
    "    .build();\n",
    "Iterator<SpansResponseChunk> traceProto = queryService.findTraces(\n",
    "    FindTracesRequest.newBuilder().setQuery(query).build());\n",
    "\n",
    "List<Span> protoSpans = new ArrayList<>();\n",
    "while (traceProto.hasNext()) {\n",
    "  protoSpans.addAll(traceProto.next().getSpansList());\n",
    "}\n",
    "Trace traces = Converter.toModel(protoSpans);\n",
    "Graph graph = GraphCreator.create(traces);\n",
    "\n",
    "Set<io.jaegertracing.analytics.model.Span> errorSpans = NumberOfErrors.calculate(graph);\n",
    "Map<String, Map<String, Integer>> result = new LinkedHashMap<>();\n",
    "for (io.jaegertracing.analytics.model.Span errorSpan : errorSpans) {\n",
    "  for (io.jaegertracing.analytics.model.Span.Log log : errorSpan.logs) {\n",
    "    String err = log.fields.get(Tags.ERROR.getKey());\n",
    "    if (err != null) {\n",
    "      Map<String, Integer> traceIdCount = result.get(err);\n",
    "      if (traceIdCount == null) {\n",
    "        traceIdCount = new LinkedHashMap<>();\n",
    "        result.put(err, traceIdCount);\n",
    "      }\n",
    "\n",
    "      Integer count = traceIdCount.get(errorSpan.traceId);\n",
    "      if (count == null) {\n",
    "        count = 0;\n",
    "      }\n",
    "      traceIdCount.put(errorSpan.traceId, ++count);\n",
    "    }\n",
    "  }\n",
    "}\n",
    "System.out.println(\"Error type, traceID and error count:\");\n",
    "for (Map.Entry<String, Map<String, Integer>> errorMap : result.entrySet()) {\n",
    "  System.out.printf(\"error type: %s\\n\", errorMap.getKey());\n",
    "  for (Map.Entry<String, Integer> traceIdCount : errorMap.getValue().entrySet()) {\n",
    "    System.out\n",
    "        .printf(\"\\tTraceID: %s, count %d\\n\", traceIdCount.getKey(), traceIdCount.getValue());\n",
    "  }\n",
    "}\n",
    "\n",
    "int height = TraceHeight.calculate(graph);\n",
    "Map<Name, Set<Double>> networkLatencies = NetworkLatency.calculate(graph);\n",
    "System.out.printf(\"Trace height = %d\\n\", height);\n",
    "System.out.printf(\"Network latencies = %s\\n\", networkLatencies);\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Write your own data analysis with Trace DSL and Apache Gremlin"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "// Are two spans connected?\n",
    "TraceTraversal<Vertex, Vertex> traversal = graph.traversal(TraceTraversalSource.class)\n",
    "        .hasName(\"HTTP GET: /customer\")\n",
    "        .repeat(__.out())\n",
    "        .until(__.hasName(\"SQL SELECT\"));\n",
    "\n",
    "traversal.forEachRemaining(v -> Util.printVertex(v));\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Java",
   "language": "java",
   "name": "java"
  },
  "language_info": {
   "codemirror_mode": "java",
   "file_extension": ".jshell",
   "mimetype": "text/x-java-source",
   "name": "Java",
   "pygments_lexer": "java",
   "version": "11.0.6+10"
  },
  "pycharm": {
   "stem_cell": {
    "cell_type": "raw",
    "metadata": {
     "collapsed": false
    },
    "source": []
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
